#include <modules\fileTrajectoryModule.h>
#include <geo\mercatorProjection.h>
#include <geo\osmio.h>
#include <geo\track.h>
#include <model.h>

#include <Poco\Path.h>
#include <Poco\File.h>

#include <iostream>
#include <fstream>

fileTrajectoryModule::fileTrajectoryModule(vec2i _tile_res, vec2i _levels_interval, int _level0_offset, string _gpxsourcefile) : dataModule() {
  tile_res = _tile_res;
  levels_interval = _levels_interval;
  level0_offset = _level0_offset;
  gpxsourcefile = _gpxsourcefile;
}

bool
fileTrajectoryModule::post(model * _model) {

  Poco::Path dir(_model->getDataStorageDir());
  dir.pushDirectory(_model->getModelName());

  Poco::File ofile(Poco::Path(dir.absolute(), _model->getModelName() + ".def"));

  ofstream output(ofile.path().c_str(), ios::app | ios::out | ios::binary);

  output << "fileTrajectoryModule" << endl;
  output << tile_res[0] << endl;
  output << tile_res[1] << endl;
  output << levels_interval[0] << endl;
  output << levels_interval[1] << endl;
  output << level0_offset << endl;

  output.close();

  osmio tracks;
  if (!tracks.open(gpxsourcefile)) return false;

  // check/create directories for all levels
  stringstream query;

  dir = _model->getDataStorageDir();
  dir.pushDirectory(_model->getModelName());
  dir.pushDirectory("global_profile");
  dir.pushDirectory(TRAJECTORY_DIR_BASE_NAME);

  for (int level = levels_interval[0]; level <= levels_interval[1]; level++) {
    stringstream str;
    str << level + level0_offset;
    dir.pushDirectory(str.str());
    Poco::File file(dir);
    file.createDirectory();
    dir.popDirectory();
  }

  for (int level = levels_interval[0]; level <= levels_interval[1]; level++) {

    // prepare trajectories from gpx dataset
    tracks.project(level);
    tracks.refine();
    tracks.encode();
    // end of preparation

    // determine chains for each [col, row] pair and store them in database
    std::vector<track<unsigned char> > etracks = tracks.getEncodedTracks();
    std::vector<track<vec2i> > rtracks = tracks.getRefinedTracks();

    for (unsigned int t = 0; t < etracks.size(); t++) {
      track<unsigned char> etrack = etracks[t];
      track<vec2i> rtrack = rtracks[t];

      for (int c = 0; c < etrack.size(); c++) {
        vec2i ritem = rtrack[c];

        // encode the chain
        unsigned int chain = 0;
        int i = 0;
        for (; i < CHAIN_SIZE; i++) {
          if (c + i >= etrack.size()) break;
          chain += etrack[c + i];
          chain = chain << 3;
        }

        chain += i; // encode chain size

        if (i > 0) {
          chains[ritem.y][ritem.x].push_back(chain);
        }
      }
    }

    map<unsigned int, map<unsigned int, vector<unsigned int> > >::iterator row;
    map<unsigned int, vector<unsigned int> >::iterator col;
    vector<unsigned int>::iterator chainit;

    for (row = chains.begin(); row != chains.end(); row++) {
      int row_id = row->first;
      for (col = row->second.begin(); col != row->second.end(); col++) {
        int col_id = col->first;

        int row_prefix = row_id / 1024;
        int row_index  = row_id % 1024;

        int col_prefix = col_id / 1024;
        int col_index  = col_id % 1024;

        stringstream str; 
        str << levels_interval[1] - level + level0_offset;
        dir.pushDirectory(str.str()); 

        str.str("");
        str << col_prefix;
        dir.pushDirectory(str.str()); 

        str.str("");
        str << col_index;
        dir.pushDirectory(str.str()); 

        str.str("");
        str << row_prefix;
        dir.pushDirectory(str.str());

        Poco::File destination_dir(dir);
        destination_dir.createDirectories();

        str.str("");
        str << row_index << ".mchs";

        Poco::File file(Poco::Path(dir.absolute().toString(), str.str()));
        file.createFile();

        // col_prefix\col_index\row_prefix\row_index.dat
        ofstream output(file.path().c_str(), ios::out | ios::binary);
        for (chainit = col->second.begin(); chainit != col->second.end(); chainit++) {
          unsigned int value = *chainit;
          output.write((const char *) &value, sizeof(unsigned int));
        }
        output.close();

        dir.popDirectory();
        dir.popDirectory();
        dir.popDirectory();
        dir.popDirectory();
      }
    }

    chains.clear();
  }

  return true;
}